﻿using System;
using System.Diagnostics;
using Gwn.Library.MvpVm.Constants;
using Gwn.Library.MvpVm.Extensions;
using Gwn.Library.MvpVm.Interfaces;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Unity;

namespace Gwn.Library.MvpVm.Base
{
    /// <summary>
    /// Module base class
    /// </summary>
    public class ModuleBase : ClassBase, IModule
    {
        #region [Dependency] Property: RegionManager
        private IRegionManager _regionManager;
        /// <summary>
        /// Gets or sets the RegionManager.
        /// </summary>
        /// <value>The start date.</value>
        [Dependency]
        public IRegionManager RegionManager
        {
            get { return _regionManager; }
            set
            {
                _regionManager = value;
                RegionManagerPropertySet();
            }
        }
        /// <summary>
        /// Called by RegionManager property setter when RegionManager is set 
        /// by Unity container.  Provides base and opportunity to do global
        /// work prior to calling virtual method
        /// </summary>
        /// <value>The start date.</value>
        private void RegionManagerPropertySet()
        {
            HandleRegionManagerPropertyWhenSet();
        }

        /// <summary>
        /// Called by RegionManagerPropertySet() when RegionManager is set by Unity container
        /// </summary>
        /// <value>The start date.</value>
        protected virtual void HandleRegionManagerPropertyWhenSet()
        {
            // Intended to be overridden
        }


        #endregion 
        #region [Dependency] Property: RegionViewRegistry 
        private IRegionViewRegistry _regionViewRegistry;
        /// <summary>
        /// Gets or sets the RegionViewRegistry.
        /// </summary>
        /// <value>The start date.</value>
        [Dependency]
        public IRegionViewRegistry RegionViewRegistry
        {
            get { return _regionViewRegistry; }
            set
            {
                _regionViewRegistry = value;
                RegionViewRegistryPropertySet();
            }
        }


        /// <summary>
        /// Called by RegionViewRegistry property setter when RegionViewRegistry 
        /// is set by Unity container.  Provides base and opportunity to do global
        /// work prior to calling virtual method
        /// </summary>
        /// <value>The start date.</value>
        private void RegionViewRegistryPropertySet()
        {
            HandleRegionViewRegistryPropertyWhenSet();
        }

        /// <summary>
        /// Called by RegionViewRegistryPropertySet() when RegionViewRegistry is set by Unity container
        /// </summary>
        /// <value>The start date.</value>
        protected virtual void HandleRegionViewRegistryPropertyWhenSet()
        {
            // Intended to be overridden
        }
        #endregion 

        /// <summary>
        /// Gets or sets the presenter.
        /// </summary>
        /// <value>The presenter.</value>
        public IPresenter Presenter { get; set; }

        // Initialize the region name for the main presenter
        private string _presenterRegion = ConstantRegions.MainRegion;
        /// <summary>
        /// Gets or sets the presenter region.
        /// </summary>
        /// <value>The presenter region.</value>
        public string PresenterRegion
        {
            get { return _presenterRegion; }
            set { _presenterRegion = value; }
        }

        /// <summary>
        /// Called by Prism catalog manager.  Provides
        /// hook to register types/views and initialize
        /// the presenter
        /// </summary>
        public void Initialize()
        {
            try
            {
                Logger.LogDebug("Initialize", GetType());

                // Provide hooks for registrations
                RegisterTypes();
                var presenter = RegisterViews();

                // Initialize
                if (presenter != null)
                {
                    presenter.Initialize();

                    // If a PresenterRegion was specified (default) then
                    // register the presenters view with it
                    if (PresenterRegion != null)
                        RegionViewRegistry
                            .RegisterViewWithRegion(PresenterRegion, () => presenter.View);
                    else
                        Logger.LogDebug("PresenterRegion was not set!  Bypassing view registration", GetType());

                    InitializeModule();

                    presenter.Initialized();
                }
                else
                    InitializeModule();

            }
            catch (Exception ex)
            {
                Debug.WriteLine(string.Format(
                    "ERROR in [{0}] {1}{2}",
                    GetType().Name,
                    ex.Message,
                    ex.StackTrace));
            }
        }

        /// <summary>
        /// Initializes the module after the module's 
        /// types and presenter is initialized
        /// </summary>
        protected virtual void InitializeModule()
        {
            Logger.LogDebug("InitializeModule", GetType());
        }

        /// <summary>
        /// Registers the types.  Called before RegisterViews()
        /// </summary>
        protected virtual void RegisterTypes()
        {
            Logger.LogDebug("RegisterTypes", GetType());
        }
        
        /// <summary>
        /// Registers the views.  The last call made to the
        /// Module infrastructure - returns module presenter
        /// </summary>
        protected virtual IPresenter RegisterViews()
        {
            Logger.LogDebug("RegisterViews", GetType());

            // Resolve the main presenter - We'll let the
            // default logic (in Initialize) register the
            // resulting view
            Presenter = Container.Resolve<IPresenter>();

            return Presenter;
        }

    }
}
